<?php
require_once 'Zend/Controller/Action/Helper/Abstract.php';

class HTech_Controller_Action_Helper_Chart extends Zend_Controller_Action_Helper_Abstract
{
    protected $_colors = array(
        '#cc00cc','#00cc00','#00cccc','#cccc00','#cc8800','#ffcc00',
        '#7b4343','#676690','#734e71','#3e7773','#6d6c00','#49734d',
        '#ae4040','#5f5bff','#ff6df6','#00b7ac','#bbb900','#00b312'
    );
    protected $_gridColor = '#eeeef0';
    protected $_backgroundColor = '#ffffff';
    
    function __construct()
    {
        $this->chart = new OFC_Chart();
        $this->chart->set_bg_colour($this->_backgroundColor);
        $this->chart->set_title(new OFC_Elements_Title( date("D M d Y") ));
        
        $this->x_axis = new OFC_Elements_Axis_X();
        $this->x_axis->set_grid_colour($this->_gridColor);
        $this->chart->set_x_axis( $this->x_axis );
        
        $this->y_axis = new OFC_Elements_Axis_Y();
        $this->y_axis->set_grid_colour($this->_gridColor);
        $this->chart->add_y_axis( $this->y_axis );
        
        $this->x_legend = new OFC_Elements_Legend_X();
        $this->x_legend->set_style('{}');
        $this->chart->set_x_legend( $this->x_legend );                         
     
        $this->y_legend = new OFC_Elements_Legend_Y();
        $this->y_legend->set_style( '{font-size: 11px;}' );
        $this->chart->set_y_legend( $this->y_legend );
        
        $this->x_labels = new OFC_Elements_Axis_X_Label_Set();
        $this->x_axis->set_labels( $this->x_labels );
    }   
    
    public function getChart()
    {
        return $this->chart;
    }
    
    /*
     * The bar chart supports series (a, b, c, etc.)
     * Example of $data
     * Change a, b, etc., by actual series names
     * Array(
     *   'a' => Array(x1 => a1, x2 => a2),
     *   'b' => Array(x1 => b1, x2 => b2),
     *   'c' => Array(x1 => c1, x2 => c2)
     * )
     */
    public function bar($data,$xLegend,$yLegend)
    {
        $c = 0; 
        $max = 0;
        foreach ($data as $key => $val)
        {
            $bar[$c] = new OFC_Charts_Bar();
            $bar[$c]->set_values( array_values($val) );
            $bar[$c]->colour = $this->_colors[$c];            
            $bar[$c]->text = $key;            
            $this->chart->add_element( $bar[$c] );            
            foreach($val as $v) $max = max($v,$max);
            $c++;
        }
        $max = 10*(ceil($max/10));                
        $xLabels = array(); 
        foreach(current($data) as $i => $j) $xLabels['labels'][] = strval($i);       
        
        $this->x_axis->set_labels( $xLabels );
        $this->y_axis->set_range( 0, $max, $max/5 );
        $this->x_legend->text = $xLegend;      
        $this->y_legend->text = $yLegend;       
        return $this->chart;
    }   
    
    /*
     * The barStack chart supports series (a, b, c, etc.)
     * Example of $data
     * Change a, b, etc., by actual series names
     * Array(
     *   'x1' => Array(a => a1, b => b1, c => c1),
     *   'x2' => Array(a => a2, b => b2, c => c1),
     *   'x3' => Array(a => a3, b => b3, c => c3)
     * )
     */
    public function barStack($data,$xLegend,$yLegend,$options = array())
    {
        $setLegend = isset($options['legend']) ? $options['legend'] : true;
        $bar_stack = new OFC_Charts_Bar_Stack();  
        if(isset($options['alpha'])) $bar_stack->set_alpha($options['alpha']);
        $bar_stack->set_tooltip('#val#');
        $c = isset($options['color_offset']) ? $options['color_offset'] : 0;
        $min = $max = 0;
        $legend = array();
        if(count($data) > 0) {
            $min = $max = reset(reset($data));
            if($setLegend)
                foreach (current($data) as $k => $v) 
                    $legend[] = new OFC_Charts_Bar_Stack_Key($this->_colors[$c++], $k, 13);
        }
        $bar_stack->set_keys($legend);        
        $xLabels = array();
        $stack = array();
        foreach ($data as $key => $val) {
            $xLabels['labels'][] = strval($key);
            $c = isset($options['color_offset']) ? $options['color_offset'] : 0;
            $sum = 0;
            foreach ($val as $k => $v) {
                $stack[$key][] = new OFC_Charts_Bar_Stack_Value($v, $this->_colors[$c++]);
                $sum = $sum + $v;
                $min = min($v,$min);
            }
            $max = max($sum,$max);
        }    
        foreach ($stack as $key => $val) $bar_stack->append_stack($val);  
        
        $range = $this->_range($min,$max,$options);
        
        $this->chart->add_element( $bar_stack ); 
        $this->x_axis->set_labels( $xLabels );
        $this->y_axis->set_range( $range['min'], $range['max'], $range['step'] );
        $this->x_legend->text = $xLegend;      
        $this->y_legend->text = $yLegend;  
        return $this->chart;
    }
 
    public function lineStack($data,$xLegend,$yLegend,$options = array())
    {   
        $sum = array_flip(array_keys(reset($data)));
        array_walk($sum, function(&$value) {$value = 0; });
        
        foreach($data as $k1 => $v1)
            foreach($v1 as $k2 => $v2) {
                $sum[$k2] = $sum[$k2] + $v2;
                $data[$k1][$k2] = $sum[$k2];
            }
         return $this->line($data,$xLegend,$yLegend,$options = array());
    }
           
    public function line($data,$xLegend,$yLegend,$options = array())
    {
        /*
         * The line chart supports several lines (a, b, c, etc.)
         * Example of $data
         * Change a, b, etc., by actual line names
         */
        /*
        $data = array(
            'a' => array('x1' => 1, 'x2' => 2, 'x3' => 3, 'x4' => 5, 'x5' => 3),
            'b' => array('x1' => 2, 'x2' => 3, 'x3' => 4, 'x4' => 2, 'x5' => 1),
            'c' => array('x1' => 2, 'x2' => 3, 'x3' => 1, 'x4' => 5, 'x5' => 4)
        );
         * 
         */
        $setLegend = isset($options['legend']) ? $options['legend'] : true;
        $c = 0;        
        $min = $max = 0;
        
        if(count($data) > 0) {
            $min = $max = reset(reset($data));
            $this->x_labels->set_labels(array_keys(reset($data)));
        }
        
        foreach($data as $k => $v) {
            if(!isset($this->_colors[$c+1])) break;
            $line = new OFC_Charts_Line(); 
            $line->set_default_dot_style(new OFC_Charts_Line_Dot());
            if($setLegend) $line->text = $k;   
            $line->set_colour($this->_colors[$c++]);
            $line->set_values(array_values($v));
            $this->chart->add_element($line);
            foreach($v as $value) {
                $min = min($value,$min);
                $max = max($value,$max);
            }
        }
        $range = $this->_range($min,$max,$options);
        
        $this->x_legend->text = $xLegend;
        if(isset($options['x_axis_steps'])) $this->x_axis->set_steps($options['x_axis_steps']);
        if(isset($options['x_labels_steps'])) $this->x_labels->set_steps($options['x_labels_steps']);
                 
        $this->y_legend->text = $yLegend;
        $this->y_axis->set_range( $range['min'], $range['max'], $range['step'] );
        
        return $this->chart;
    }
    
    public function areaStack($data,$xLegend,$yLegend,$options = array())
    {   
        $sum = array_flip(array_keys(reset($data)));
        array_walk($sum, function(&$value) {$value = 0; });
        
        foreach($data as $k1 => $v1)
            foreach($v1 as $k2 => $v2) {
                $sum[$k2] = $sum[$k2] + $v2;
                $data[$k1][$k2] = $sum[$k2];
            }
         return $this->area($data,$xLegend,$yLegend,$options);
    }
                  
    public function area($data,$xLegend,$yLegend,$options = array())
    {
        /*
         * The line chart supports several lines (a, b, c, etc.)
         * Example of $data
         * Change a, b, etc., by actual line names
         */
        /*
        $data = array(
            'a' => array('x1' => 1, 'x2' => 2, 'x3' => 3, 'x4' => 5, 'x5' => 3),
            'b' => array('x1' => 2, 'x2' => 3, 'x3' => 4, 'x4' => 2, 'x5' => 1),
            'c' => array('x1' => 2, 'x2' => 3, 'x3' => 1, 'x4' => 5, 'x5' => 4)
        );
         * 
         */
        $data = array_reverse($data);
        $c = 0;
        $min = $max = reset(reset($data));
        foreach($data as $k => $v) {
            $c++;
            if(!isset($this->_colors[$c+1])) break;
            $area = new OFC_Charts_Area();
            $area->text = $k;   
            $area->set_colour($this->_colors[$c]); 
            $area->set_fill_colour($this->_colors[$c]);
            $area->set_values(array_values($v));
            $area->set_width(2);
            $dot = new OFC_Charts_Area_Dot();
            $dot->set_size(2);
            $dot->set_color($this->_colors[$c]);
            $area->set_default_dot_style($dot);
            $this->chart->add_element($area);
            foreach($v as $value) {
                $min = min($value,$min);
                $max = max($value,$max);
            }
        }
        $range = $this->_range($min,$max,$options);
        
        $this->x_legend->text = $xLegend;
        $this->x_labels->set_labels(array_keys(reset($data)));
        if(isset($options['x_axis_steps'])) $this->x_axis->set_steps($options['x_axis_steps']);
        if(isset($options['x_labels_steps'])) $this->x_labels->set_steps($options['x_labels_steps']);
                 
        $this->y_legend->text = $yLegend;
        $this->y_axis->set_range( $range['min'], $range['max'], $range['step'] );
        
        return $this->chart;
    }
    
    public function setYAxisRange($min,$max,$step)
    {
        $this->y_axis->set_range( $min, $max, $step );
        return $this->chart;
    }
    
    private function _range($min,$max,$options)
    {
        if($min == $max) {
            $min = 0;
            $step = $max/5;
        } else {
            $step = isset($options['step']) ? $options['step'] : ($max - $min)/5;
        }
        if(($min > 0)&&($min < 2*$step)) {
            $min = 0;
            $max = $max + $step;
        }
        $min = isset($options['min']) ? $options['min'] : $min;
        $max = isset($options['max']) ? $options['max'] : $max;
        $step = isset($options['step']) ? $options['step'] : $step;
        return array('min' => $min, 'max' => $max, 'step' => $step);
    }

}
